﻿using Furion;
using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using UpperComputer.Core.Entities;
using YFurion.Entities;
using YFurion.EntityFrameworkCore;
using YFurion.Utils;

namespace UpperComputer.EntityFramework.Core
{
    public class MasterDbContext : WriteReadDbContext<MasterDbContext, MasterDbContextLocator>
    {
        public MasterDbContext(DbContextOptions<MasterDbContext> options) : base(options)
        {
        }

        protected override void SavingChangesEventOuter(DbContextEventData eventData, InterceptionResult<int> result)
        {
            bool isAudit = App.Configuration.Get<bool>("IsAudit");
            if (!isAudit)
            {
                return;
            }

            // 获取当前事件对应上下文
            DbContext dbContext = eventData.Context;
            // 强制重新检查一边实体更改信息
            // dbContext.ChangeTracker.DetectChanges();
            // 获取所有更改，删除，新增的实体，但排除审计实体（避免死循环）
            List<EntityEntry> entities = dbContext.ChangeTracker.Entries()
                .Where(u => u.Entity.GetType() != typeof(LoginInOrOutLog) && u.Entity.GetType()!= typeof(AuditLog) && (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added))
                .ToList();
            // 获取所有已更改的实体
            foreach (EntityEntry entityEntry in entities)
            {
                // 获取实体类型
                Type entityType = entityEntry.Entity.GetType();
                // 获取所有实体有效属性，排除 [NotMapper] 属性
                IReadOnlyList<IProperty> props = entityEntry.OriginalValues.Properties;
                // 获取实体当前（现在）的值
                PropertyValues currentValues = entityEntry.CurrentValues;
                // 获取数据库中实体的值
                PropertyValues databaseValues = entityEntry.GetDatabaseValues();
                // 遍历所有属性
                foreach (IProperty prop in props)
                {
                    bool isNotAdd = entityEntry.State != EntityState.Added;
                    // 获取属性名
                    string propName = prop.Name;
                    if (isNotAdd &&
                        (propName == nameof(ICreationAudited.CreationTime) || propName == nameof(ICreationAudited.CreatorUserId)))
                    {
                        continue;
                    }

                    // 获取现在的实体值
                    object newValue = currentValues[propName];
                    object oldValue = null;
                    // 如果是新增数据，则 databaseValues 为空，所以需要判断一下
                    if (databaseValues != null)
                    {
                        oldValue = databaseValues[propName];
                    }

                    string newValueStr = newValue?.ToString(), oldValueStr = oldValue?.ToString();
                    if (isNotAdd &&
                        ((newValueStr == null && oldValueStr == null) || (newValueStr != null && oldValueStr != null && newValueStr == oldValueStr)))
                    {
                        continue;
                    }

                    // 插入审计日志表，Audit 是你自定义的实体
                    dbContext.Set<AuditLog>().Add(new AuditLog
                    {
                        Id = YIDGenerator.NextId(),
                        UserId = YSession.SubjectId,    // 操作人
                        Account = YSession.Account,
                        UserName = YSession.UserName,
                        TableName = entityType.Name,    // 表名
                        ColumnName = propName,  // 更新的列
                        NewValue = newValueStr,    // 新值
                        OldValue = oldValueStr,    // 旧值
                        Operation = entityEntry.State.ToString(),  // 操作方式：新增、更新、删除
                        OperationTime = DateTime.Now // 操作时间,                       
                    });
                }
            }
        }
    }
}